package com.dd.cloud.user.service.paynotice;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.dd.cloud.common.config.common.SpringContextJobUtil;
import com.dd.cloud.common.constants.OrderConstants;
import com.dd.cloud.common.constants.RedisKeyConstants;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.user.entity.order.OrderFlow;
import com.dd.cloud.user.entity.order.OrderPay;
import com.dd.cloud.user.enums.ExceptionEnum;
import com.dd.cloud.user.service.consule.IConsultSubscribeService;
import com.dd.cloud.user.service.order.IOrderFlowService;
import com.dd.cloud.user.service.order.IOrderPayService;
import com.dd.cloud.user.service.paynotice.promode.NoticeContext;
import com.dd.cloud.user.service.paynotice.promode.NoticeService;
import com.dd.cloud.user.service.paynotice.promode.NoticeType;
import com.dd.cloud.user.service.paynotice.promode.NoticeTypeImpl;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.zk.pay.channel.IChannelNoticeService;
import com.zk.pay.constants.CS;
import com.zk.pay.model.MchInfoConfigContext;
import com.zk.pay.rqrs.msg.ChannelRetMsg;
import com.zk.pay.util.RequestKitBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 回调处理统一业务
 */
@Service
@Slf4j
public class NoticeOrderService {
    @Autowired
    private IOrderPayService orderPayService;
    @Autowired
    private IOrderFlowService orderFlowService;
    @Autowired
    private NoticeContext noticeContext;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;
    @Autowired
    private RequestKitBean requestKitBean;

    @Autowired
    private IConsultSubscribeService consultSubscribeService;

    /**
     * 支付回调
     *
     * @param request
     * @param redisKey 支付的redis的key
     * @return
     */
    public ResponseEntity doNotice(HttpServletRequest request, String redisKey) {
        log.info(redisKey);
        // 参数有误
        if (StringUtils.isEmpty(redisKey)) {
            return ResponseEntity.badRequest().body("appid is empty");
        }
        MchInfoConfigContext mchInfoConfigContext = requestKitBean.getMchInfoConfigContext(redisKey);
        // 参数有误
        if (mchInfoConfigContext == null) {
            return ResponseEntity.badRequest().body("url is error");
        }
        //查询支付回调接口是否存在 用来获取回调参数和返回信息
        IChannelNoticeService payNotifyService = SpringContextJobUtil.getBean(mchInfoConfigContext.getPayParam().getPayType() + "payChannelNoticeService", IChannelNoticeService.class);

        // 支付通道接口实现不存在
        if (payNotifyService == null) {
            log.error("{}, interface not exists ", payNotifyService);
            return ResponseEntity.badRequest().body("[" + redisKey + "] interface not exists");
        }

        // 解析订单号 和 请求参数
        MutablePair<String, Object> mutablePair = payNotifyService.parseParams(request, mchInfoConfigContext);
        if (mutablePair == null) { // 解析数据失败， 响应已处理
            log.error("{}, mutablePair is null ", mutablePair);
            throw new ZekeException(500, "解析数据异常！");
        }
        //调起接口的回调判断 返回信息
        ChannelRetMsg notifyResult = payNotifyService.doNotice(request, mutablePair.getRight(), mchInfoConfigContext);

        //查询业务回调接口是否存在 用来处理业务信息
        PayNoticeService payNoticeService = SpringContextJobUtil.getBean(mchInfoConfigContext.getPayParam().getPayType() + "payNoticeService", PayNoticeService.class);
        // 回调通道接口实现不存在
        if (payNoticeService == null) {
            log.error("{}, interface not exists ", payNotifyService);
            return ResponseEntity.badRequest().body("[" + redisKey + "] interface not exists");
        }
        payNoticeService.payNotify(request, mutablePair, mchInfoConfigContext);
        return notifyResult.getResponseEntity();
    }


    /**
     * 退款回调
     *
     * @param request
     * @param redisKey
     * @return
     */
    public ResponseEntity refundNotice(HttpServletRequest request, String redisKey) throws IOException {
        // 参数有误
        if (StringUtils.isEmpty(redisKey)) {
            return ResponseEntity.badRequest().body("ifCode is empty");
        }
        MchInfoConfigContext mchInfoConfigContext = requestKitBean.getMchInfoConfigContext(redisKey);
        // 参数有误
        if (mchInfoConfigContext == null) {
            return ResponseEntity.badRequest().body("url is error");
        }
        //查询支付回调接口是否存在 用来获取回调参数和返回信息
        IChannelNoticeService payNotifyService = SpringContextJobUtil.getBean(mchInfoConfigContext.getPayParam().getPayType() + "payChannelNoticeService", IChannelNoticeService.class);

        // 支付通道接口实现不存在
        if (payNotifyService == null) {
            log.error("{}, interface not exists ", payNotifyService);
            return ResponseEntity.badRequest().body("[" + redisKey + "] interface not exists");
        }

        // 解析订单号 和 请求参数
        WxPayRefundNotifyResult.ReqInfo mutablePair = (WxPayRefundNotifyResult.ReqInfo) payNotifyService.refundParseParams(request, mchInfoConfigContext);
        if (mutablePair == null) { // 解析数据失败， 响应已处理
            log.error("{}, mutablePair is null ", mutablePair);
            throw new ZekeException(500, "解析数据异常！");
        }
        //调起接口的回调判断 返回信息
        ChannelRetMsg notifyResult = payNotifyService.doRefundNotice(request, mutablePair);

        //查询业务回调接口是否存在 用来处理业务信息
        PayNoticeService payNoticeService = SpringContextJobUtil.getBean(mchInfoConfigContext.getPayParam().getPayType() + "payNoticeService", PayNoticeService.class);
        // 回调通道接口实现不存在
        if (payNoticeService == null) {
            log.error("{}, interface not exists ", payNotifyService);
            return ResponseEntity.badRequest().body("[" + redisKey + "] interface not exists");
        }
        payNoticeService.refundNotify(request, mutablePair);
        return notifyResult.getResponseEntity();
    }


    /**
     * //需重新计算主订单的实际支付金额和处方的实际金额
     *
     * @param orderNo 订单表头编号
     * @param flowNo  订单流水号
     * @param sta     类型 1支付, 2退款
     */
    public void calcMainOrder(HttpServletRequest request, String orderNo, String flowNo, int sta) {
        QueryWrapper<OrderPay> q3 = new QueryWrapper<>();
        q3.lambda().eq(OrderPay::getOrderNo, orderNo);
        OrderPay header = orderPayService.getOne(q3);
        if (header == null) {
            throw new ZekeException(ExceptionEnum.UPDATE_ORDER_STATUS_ERROR);
        }
        //订单删除业务 处理订单删除后用户误支付后 进行退款操作 值为0正常流程 值为1进行处方退款操作
        int delBo = 0;
        if (header.getStatus() == OrderConstants.Status.DEL && sta == 1) {
            delBo = 1;
            header.setStatus(OrderConstants.Status.NOPAY);
        }
        //手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            //流水实际金额汇总=付款-退款
            int flowTotalFee = 0;
            OrderFlow record = new OrderFlow();
            record.setOrderNo(orderNo);
            QueryWrapper<OrderFlow> q = new QueryWrapper<>();
            q.lambda().eq(OrderFlow::getOrderNo, orderNo);
            List<OrderFlow> paymentFlows = orderFlowService.list(q);
            for (OrderFlow flow : paymentFlows) {
                if (flow.getTotalFee() != null && flow.getStatus() == OrderConstants.FlowStatus.PAY) {
                    switch (flow.getFlowType()) {
                        case OrderConstants.FlowType.PAY:
                            flowTotalFee += flow.getTotalFee();
                            break;
                        case OrderConstants.FlowType.REFUND:
                            flowTotalFee = flowTotalFee - flow.getTotalFee();
                            break;
                        default:
                    }
                }
            }
            header.setUpdateDate(LocalDateTime.now());
            //更新主订单实付金额
            header.setActualPay(flowTotalFee);
            //更新订单表头状态
            if (header.getStatus() == OrderConstants.Status.PAY && sta == 1) {
                dataSourceTransactionManager.rollback(transactionStatus);
                //已是支付状态, 不处理
                return;
            }
            if (header.getStatus() == OrderConstants.Status.FULLREFUND && sta == 2) {
                dataSourceTransactionManager.rollback(transactionStatus);
                //已是全额退款状态, 不处理
                return;
            }
            //1、1=未支付--->2=已支付
            if (header.getStatus() == 1) {
                //1=未支付
                header.setStatus(OrderConstants.FlowStatus.PAY);
            }
            //如果实付金额和应付金额都为0，状态改为已退款
            if (header.getActualPay() == 0) {
                header.setStatus(OrderConstants.Status.FULLREFUND);
            }
            UpdateWrapper<OrderPay> q2 = new UpdateWrapper<>();
            q2.lambda().eq(OrderPay::getOrderNo, orderNo);
            boolean count = orderPayService.update(header, q2);
            if (!count) {
                throw new ZekeException(ExceptionEnum.UPDATE_ORDER_STATUS_ERROR);
            }
            if (delBo == 0) {
                //修改对应的用户购买产品信息
                payBatchOrSin(request, header, flowNo, sta);
            }
            //如果是问诊订单还需修改问诊订单状态
//            String single = header.getProduct();
//            if (OrderConstants.Product.SINGLE.equals(single)) {
//                String id = header.getServerNo();
//                if (StringUtils.isNotBlank(id)) {
//                    Integer consultId = Integer.valueOf(id);
//                    log.info("修改问诊订单状态,问诊订单id为:{}",consultId);
//                    LambdaUpdateWrapper<ConsultSubscribe> update = new LambdaUpdateWrapper<>();
//                    update.eq(ConsultSubscribe::getStatus, ConsultConstants.Status.REFUND)
//                            .set(ConsultSubscribe::getId,consultId);
//                    consultSubscribeService.update(update);
//                    log.info("修改问诊订单状态成功");
//                }
//            }
            //手动提交事务
            dataSourceTransactionManager.commit(transactionStatus);
            //清除处方详情缓存
            redisTemplate.delete(RedisKeyConstants.PRES_DETAIL_REDIS_KEY + header.getServerNo());
            if (delBo == 1) {
                orderPayService.refund(orderNo, 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //手动回滚事务
            dataSourceTransactionManager.rollback(transactionStatus);
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
    }

    /**
     * 判断回调是购买哪一个产品
     *
     * @param request
     * @param header
     * @param flowNo
     * @param sta
     */
    @Transactional
    public void payBatchOrSin(HttpServletRequest request, OrderPay header, String flowNo, int sta) {
        log.info("支付产品回调, {}, {}", flowNo, sta);
        String product = header.getProduct();
        if (StringUtils.isBlank(header.getProduct())) {
            product = CS.NOTICE_CHANNEL.PRE;
        }
        /**
         * 固定处方产品回调
         */
        NoticeType noticeType = new NoticeTypeImpl(OrderConstants.getPayOrderCanalType(sta), product);
        log.info("回调处理:{}",noticeType);
        NoticeService noticeService = noticeContext.getNoticeService(noticeType);
        noticeService.notice(request, header, flowNo);
    }

}
